package com.service.screenReception.task;

import com.alibaba.fastjson.JSONArray;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.service.config.utils.JsonXMLUtils;
import com.service.config.utils.ModelMapperUtil;
import com.service.config.utils.RedisUtil;
import com.service.screenReception.dao.*;
import com.service.screenReception.dto.*;
import com.service.screenReception.entity.Assembly;
import com.service.screenReception.entity.ProgrammeInfo;
import com.service.screenReception.entity.ScreenUser;
import com.service.screenReception.entity.UserServiceInfo;
import com.service.screenReception.enums.AssemblyEnum;
import com.service.screenReception.service.UserServiceInfoService;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.service.config.utils.*;
import com.service.screenReception.ScreenReceptionApplication;
import com.service.screenReception.dao.ProgrammeInfoDao;
import com.service.screenReception.dao.ScreenUserDao;
import com.service.screenReception.dto.*;
import com.service.screenReception.entity.ProgrammeInfo;
import com.service.screenReception.entity.ScreenUser;
import com.service.screenReception.enums.AssemblyEnum;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.service.config.utils.DateUtil.*;

import static com.service.config.utils.DateUtil.*;


import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: CloudCampusService
 * @description: 定时任务
 * @author: rui
 * @create: 2021-03-30 15:35
 **/
@Component
@Async
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ScreenReceptionApplication.class)
public class ScheduleService {
    private final ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
    private final ExecutorService product = new ThreadPoolExecutor(20,40,200L, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<Runnable>(),namedThreadFactory);
    @Resource
    RedisUtil redisUtil;
    @Resource
    CloudCampusApi cloudCampusApi;
    @Resource
    ScreenUserDao screenUserDao;

    @Resource
    ProgrammeInfoDao programmeInfoDao;
    @Resource
    UserServiceInfoService userServiceInfoService;
    @Resource
    UserInfoDao userInfoDao;
    @Resource
    ScreenModelDao screenModelDao;
    @Resource
    AssemblyDao assemblyDao;

   // @Scheduled(fixedDelay = 20000)
    @Scheduled(cron = "0 */5 * * * ?")
//    @Async("taskExecutor")
    public void getLoginUserDispose() {

        //查找在线用户Api账号列表
        List<ScreenUser> userInfos = new ArrayList<>();
        List<ScreenUser> screenUsers = screenUserDao.queryAll(new ScreenUser());
        screenUsers.forEach(userInfo -> {
            Set<String> strings = redisUtil.redisLike(userInfo.getUserId());
            if (strings.size()>0 ) {
                userInfos.add(userInfo);
            }
        });

        //筛选出来用户api账号状态正常的获取数据
        List<ScreenUser> list = new ArrayList<>();
        userInfos.forEach(user -> {
            if (user.isStatus()) {
                if (user.getDomain() == null || "".equals(user.getDomain())) {
                    user.setDomain("naas");
                }
                list.add(user);
            }
        });

        if (list.size() > 0) {
            //根据用户id分组
            Map<String, List<ScreenUser>> map = new HashMap<>();
            list.stream().collect(Collectors.groupingBy(ScreenUser::getUserId))
                    .forEach(map::put);
            map.entrySet().forEach(userList -> {
                String assemblyInfo = "";
                ProgrammeInfo programmeInfo = new ProgrammeInfo();
                programmeInfo.setUserId(userList.getKey());
                List<ProgrammeInfo> programmeInfos = programmeInfoDao.queryAll(programmeInfo);
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    if (programmeInfo1.getStatus()) {
                        getAssembly(programmeInfo1.getLayoutInfo(),userList.getValue());
                    }
                }
            });

        } else {
            log.info("The Online User list is null!");
        }
    }

    /**
     * 中午11:59:59秒 23:59:59秒 查询链路数据
     */
    @Test
    @Scheduled(cron = "59 59 11,23 * * ?")
    @Async("taskExecutorConfig")
    public void getLoginUserLinkInfo() {

        //查找在线用户Api账号列表
        List<ScreenUser> userInfos = new ArrayList<>();
        List<ScreenUser> screenUsers = screenUserDao.queryAll(new ScreenUser());
        screenUsers.forEach(userInfo -> {
            Set<String> strings = redisUtil.redisLike(userInfo.getUserId());
            if (strings.size()>0 ) {
                userInfos.add(userInfo);
            }
        });

        //筛选出来用户api账号状态正常的获取数据
        List<ScreenUser> list = new ArrayList<>();
        userInfos.forEach(user -> {
            if (user.isStatus()) {
                if (user.getDomain() == null || "".equals(user.getDomain())) {
                    user.setDomain("naas");
                }
                list.add(user);
            }
        });

        if (list.size() > 0) {
            //根据用户id分组
            Map<String, List<ScreenUser>> map = new HashMap<>();
            list.stream().collect(Collectors.groupingBy(ScreenUser::getUserId))
                    .forEach(map::put);
            map.entrySet().forEach(userList -> {
                ProgrammeInfo programmeInfo = new ProgrammeInfo();
                programmeInfo.setUserId(userList.getKey());
                List<ProgrammeInfo> programmeInfos = programmeInfoDao.queryAll(programmeInfo);
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    if (programmeInfo1.getStatus()) {
                        try {
                           // getLoginUserLinkInfo(programmeInfo1.getLayoutInfo(),userList.getValue());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

        } else {
            log.info("The Online User list is null!");
        }
    }

    public  void getLoginUserLinkInfo(String layoutInfo, List<ScreenUser> value) throws Exception {
        //获取站点
        List<ProgrammeInfoViewDto> assemblies = JSONArray.parseArray(layoutInfo, ProgrammeInfoViewDto.class);
        // 线程池获取数据
        List<LinkDataModel> linkDataModelList = threadPool(assemblies, value);
        //Result result = JsonXMLUtils.json2obj(PropertiesUtils.readJsonFile("linkTree.json"), Result.class);
        //List<LinkDataModel> linkDataModelList = JSONArray.parseArray(JsonXMLUtils.obj2json(result.getData()),LinkDataModel.class);
        if (linkDataModelList.size() > 0) {
            // 生成树
            List<LinkDataModel> dataModelList = linkDataModelList.stream().filter(// 过滤去重
                    distinctByKey(LinkDataModel::getLinkname)
            ).collect(Collectors.toList());
            // 获取设备数据
            List<DeviceDto> deviceInfo = getDeviceInfo(value);
            // 生成设备结构
            List<DeviceStructure> linkDeviceStructure = getLinkDeviceStructure(dataModelList,deviceInfo);
            // 整合数据
            linkDeviceStructure = mergeDevices(linkDeviceStructure);
            // 遍历设备结构确定ap层高以及与ap直接相连的设备层高
            List<DeviceStructure> deviceStructureList = forEachDevices(linkDeviceStructure, deviceInfo);
            //补齐对端的层高
            recursive(deviceStructureList);
            Map<String, List<DeviceStructure>> tree = filterDevices(deviceStructureList);
            deviceStructureList = tree.get("deviceStructureList");
            List<DeviceStructure> collect = tree.get("collect");//不和ap直连的设备层高为0的集合
            List<LinkTree> tree1 = createTree(new ArrayList<LinkTree>(), deviceStructureList);
            recursive(tree1,collect);
            // 不和ap直连或者间接相连的设备生成树
            List<LinkTree> linkTrees = directConnectionRecursive(new ArrayList<LinkTree>(), collect);
            System.out.println("json:  "+JsonXMLUtils.obj2json(tree1));
            System.out.println("collect:  "+JsonXMLUtils.obj2json(linkTrees));
        }
    }

    /**
     * 不和ap直连或者间接相连的设备生成树
     * @param tree1
     * @param collect
     */
    private List<LinkTree> directConnectionRecursive(List<LinkTree> tree1,List<DeviceStructure> collect) {
        if (tree1.size() > 0) {
            tree1.forEach(linkTree -> {
                if (linkTree.getPId() == null) {
                    linkTree.setPId("0");
                }
            });
            List<LinkTree> collect1 = tree1.stream().filter(linkTree -> linkTree.getPId().equals("1")).collect(Collectors.toList());
            for (LinkTree linkTree : collect1){
                if (collect.size() ==0 ){
                    linkTree.setPId("0");
                }
                else {
                    Iterator<DeviceStructure> iterator1 = collect.iterator();
                    while (iterator1.hasNext()) {
                        DeviceStructure deviceStructure = iterator1.next();
                        if (deviceStructure.getOppositeEnd() == 0) {
                            iterator1.remove();
                            break;
                        }
                        LinkTree linkTree2 = new LinkTree();
                        linkTree2.setId(deviceStructure.getDeviceId());
                        linkTree2.setLevel(deviceStructure.getLevel());
                        linkTree2.setName(deviceStructure.getDeviceName());
                        Iterator<DeviceStructure> iterator = deviceStructure.getDeviceStructureList().iterator();
                        while (iterator.hasNext()){
                            DeviceStructure deviceStructure1 = iterator.next();
                            if (linkTree.getId().equals(deviceStructure1.getDeviceId())) {
                                LinkTree linkTree1 = new LinkTree();
                                linkTree1.setId(linkTree.getId());
                                linkTree1.setName(deviceStructure1.getDeviceName());
                                linkTree2.setPId("1");
                                linkTree1.setLevel(deviceStructure1.getLevel()+1);
                                tree1.add(linkTree2);
                                linkTree1.setPId(deviceStructure.getDeviceId());
                                tree1.add(linkTree1);
                                deviceStructure.setOppositeEnd(deviceStructure.getOppositeEnd()-1);
                                iterator.remove();
                            }
                        }
                        linkTree.setPId("0");
                    }
                }
            }
            List<LinkTree> collect2 = tree1.stream().filter(linkTree -> linkTree.getPId().equals("1")).collect(Collectors.toList());
            if (collect2.size() > 0) {
                directConnectionRecursive(tree1,collect);
            }
        }else {
            List<LinkTree> tree = createTreeLevelEqualZero(tree1, collect);
            directConnectionRecursive(tree,collect);
        }
        return tree1;
    }

    private List<LinkTree> createTreeLevelEqualZero(List<LinkTree> tree1, List<DeviceStructure> collect) {
        List<DeviceStructure> collect1 = collect.stream().filter(deviceStructure -> deviceStructure.getOppositeEnd() > 1).collect(Collectors.toList());
        collect.removeAll(collect1);
        collect1.forEach(deviceStructure -> {
            LinkTree linkTree = new LinkTree();
            linkTree.setId(deviceStructure.getDeviceId());
            linkTree.setName(deviceStructure.getDeviceName());
            linkTree.setPId("1");
            linkTree.setLevel(deviceStructure.getLevel());
            tree1.add(linkTree);
            deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> {
                LinkTree linkTree1 = new LinkTree();
                linkTree1.setId(deviceStructure1.getDeviceId());
                linkTree1.setName(deviceStructure1.getDeviceName());
                linkTree1.setPId(linkTree.getId());
                linkTree1.setLevel(deviceStructure1.getLevel()+1);
                tree1.add(linkTree1);
            });
        });
        tree1.forEach(linkTree -> {
            List<DeviceStructure> collect2 = collect.stream().filter(deviceStructure -> deviceStructure.getDeviceId().equals(linkTree.getId())).collect(Collectors.toList());
            collect.removeAll(collect2);
        });
        if (collect.size() > 0) {
            collect.forEach(deviceStructure -> {
                LinkTree linkTree = new LinkTree();
                linkTree.setId(deviceStructure.getDeviceId());
                linkTree.setName(deviceStructure.getDeviceName());
                linkTree.setPId("0");
                linkTree.setLevel(deviceStructure.getLevel());
                tree1.add(linkTree);
                deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> {
                    LinkTree linkTree1 = new LinkTree();
                    linkTree1.setId(deviceStructure1.getDeviceId());
                    linkTree1.setName(deviceStructure1.getDeviceName());
                    linkTree1.setPId(linkTree.getId());
                    linkTree1.setLevel(deviceStructure1.getLevel()+1);
                    tree1.add(linkTree1);
                });
            });
        }
        return tree1;
    }

    /**
     * 补齐层高
     * @param tree1
     * @param collect
     * @throws Exception
     */
    private void recursive(List<LinkTree> tree1, List<DeviceStructure> collect) throws Exception {
        List<LinkTree> collect1 = tree1.stream().filter(linkTree -> linkTree.getPId().equals("1")).collect(Collectors.toList());
        for (LinkTree linkTree : collect1){
            Iterator<DeviceStructure> iterator1 = collect.iterator();
            while (iterator1.hasNext()) {
                DeviceStructure deviceStructure = iterator1.next();
                if (deviceStructure.getOppositeEnd() == 0) {
                    iterator1.remove();
                    break;
                }
                LinkTree linkTree2 = new LinkTree();
                linkTree2.setId(deviceStructure.getDeviceId());
                linkTree2.setName(deviceStructure.getDeviceName());
                Iterator<DeviceStructure> iterator = deviceStructure.getDeviceStructureList().iterator();
                while (iterator.hasNext()){
                    DeviceStructure deviceStructure1 = iterator.next();
                    if (linkTree.getId().equals(deviceStructure1.getDeviceId())) {
                        LinkTree linkTree1 = new LinkTree();
                        linkTree1.setId(linkTree.getId());
                        linkTree1.setName(deviceStructure1.getDeviceName());
                        linkTree1.setLevel(linkTree.getLevel());
                        linkTree2.setLevel(linkTree.getLevel()+1);
                        linkTree2.setPId("1");
                        tree1.add(linkTree2);
                        linkTree1.setPId(deviceStructure.getDeviceId());
                        tree1.add(linkTree1);
                        deviceStructure.setOppositeEnd(deviceStructure.getOppositeEnd()-1);
                        iterator.remove();
                    }
                }
                linkTree.setPId("0");
            }
        }
        List<LinkTree> collect2 = tree1.stream().filter(linkTree -> linkTree.getPId().equals("1")).collect(Collectors.toList());
        if (collect2.size() > 0) {
            recursive(tree1,collect);
        }
    }

    /**
     * 创建ap直连的层高以及父级id树
     * @param linkTreeList
     * @param deviceStructureList
     * @return
     */
    private List<LinkTree> createTree(List<LinkTree> linkTreeList,List<DeviceStructure> deviceStructureList) {
        deviceStructureList.forEach(deviceStructure -> {
            LinkTree linkTree = new LinkTree();
            linkTree.setId(deviceStructure.getDeviceId());
            linkTree.setLevel(deviceStructure.getLevel());
            linkTree.setName(deviceStructure.getDeviceName());
            deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> {
                LinkTree linkTree1 = new LinkTree();
                if (deviceStructure1.getLevel() > deviceStructure.getLevel()) {
                    linkTree1.setLevel(linkTree.getLevel()+1);
                    linkTree1.setPId("1");
                    linkTree1.setId(deviceStructure1.getDeviceId());
                    linkTree1.setName(deviceStructure1.getDeviceName());
                    linkTree.setPId(deviceStructure1.getDeviceId());
                    linkTreeList.add(linkTree);
                    linkTreeList.add(linkTree1);
                }else {
                    linkTree1.setLevel(deviceStructure1.getLevel());
                    linkTree1.setId(deviceStructure1.getDeviceId());
                    linkTree1.setName(deviceStructure1.getDeviceName());
                    linkTree1.setPId(linkTree.getId());
                    linkTreeList.add(linkTree1);
                    linkTreeList.add(linkTree);
                }
            });
        });
        return linkTreeList;
    }

    /**
     * 过滤掉设备层高为0的设备结构
     * @param deviceStructureList
     */
    private Map<String,List<DeviceStructure>> filterDevices(List<DeviceStructure> deviceStructureList) {
        HashMap<String,List<DeviceStructure>> map = new HashMap<String,List<DeviceStructure>>();
        List<DeviceStructure> collect = deviceStructureList.stream().filter(deviceStructure -> deviceStructure.getLevel() == 0).collect(Collectors.toList());
        if (collect.size()>0) {
            map.put("collect",collect) ;
        }
        deviceStructureList.removeAll(collect);
        map.put("deviceStructureList",deviceStructureList);
        return map;
    }

    /**
     * 创建ap直连的层高
     * @param linkDeviceStructure
     * @param deviceInfo
     * @return
     */
    private List<DeviceStructure> forEachDevices(List<DeviceStructure> linkDeviceStructure, List<DeviceDto> deviceInfo) {
        linkDeviceStructure.forEach(deviceStructure -> {
            AtomicInteger i = new AtomicInteger();
            HashMap deviceLevel = getDeviceLevel(deviceInfo, deviceStructure);
            if (deviceLevel.get("errorCode").equals("1")) {
                deviceStructure.setLevel(1);
                deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> deviceStructure1.setLevel(2));
                i.set(1);
            }else if (deviceLevel.get("errorCode").equals("2")) {
                deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> {
                    HashMap deviceLevel1 = getDeviceLevel(deviceInfo, deviceStructure1);
                    if (deviceLevel1.get("errorCode").equals("1")) {
                        deviceStructure1.setLevel(1);
                        deviceStructure.setLevel(2);
                        i.set(1);
                    }else if(deviceLevel1.get("errorCode").equals("2")){
                        if (i.get()==1) {
                            deviceStructure1.setLevel(3);
                        }else {
                            deviceStructure.setLevel(0);
                            deviceStructure1.setLevel(0);
                        }
                    }else {
                        if (i.get()==0) {
                            deviceStructure.setLevel(0);
                            deviceStructure1.setLevel(0);
                        }
                    }});
            }else {
                deviceStructure.getDeviceStructureList().forEach(deviceStructure1 -> {
                    HashMap deviceLevel1 = getDeviceLevel(deviceInfo, deviceStructure1);
                    if (deviceLevel1.get("errorCode").equals("1")) {
                        deviceStructure1.setLevel(1);
                        deviceStructure.setLevel(2);
                        i.set(1);
                    }else if(deviceLevel1.get("errorCode").equals("2")){
                        if (i.get()==1) {
                            deviceStructure1.setLevel(3);
                        }else {
                            deviceStructure.setLevel(0);
                            deviceStructure1.setLevel(0);
                        }
                    }else {
                        if (i.get()==0) {
                            deviceStructure.setLevel(0);
                            deviceStructure1.setLevel(0);
                        }
                    }});
            }
        });
        return linkDeviceStructure;
    }

    /**
     * 判断设备类型
     * @param deviceInfo
     * @param deviceStructure
     * @return
     */
    private HashMap getDeviceLevel(List<DeviceDto> deviceInfo, DeviceStructure deviceStructure) {
        List<DeviceDto> deviceDtoList = filterDevice(deviceStructure, deviceInfo);
        HashMap map = new HashMap();
        if (deviceDtoList.size() > 0 ) {
            if (deviceDtoList.get(0).getDeviceType().equals("AP") && !deviceDtoList.get(0).getDeviceModel().contains("AD")) {
                map.put("errorCode","1");
                return map;
            }else {
                map.put("errorCode","2");
                return map;
            }
        }
        map.put("errorCode","3");
        return map;
    }

    private List<DeviceStructure> mergeDevices(List<DeviceStructure> linkDeviceStructure) {
        Map<String, List<DeviceStructure>> collect = linkDeviceStructure.stream().collect(Collectors.groupingBy(DeviceStructure::getDeviceId));
        List<DeviceStructure> deviceStructureList = new ArrayList<>();
        collect.entrySet().forEach(stringListEntry -> {
            List<DeviceStructure> collect2 = linkDeviceStructure.stream().filter(deviceStructure ->
                    deviceStructure.getDeviceId().equals(stringListEntry.getKey())).collect(Collectors.toList());
            List<DeviceStructure> deviceStructureList1 = new ArrayList<>();
            stringListEntry.getValue().forEach(deviceStructure -> deviceStructureList1.addAll(deviceStructure.getDeviceStructureList()));
            List<DeviceStructure> collect1 = deviceStructureList1.stream().filter(distinctByKey(DeviceStructure::getDeviceId)).collect(Collectors.toList());
            collect2.get(0).setDeviceStructureList(collect1);
            collect2.get(0).setOppositeEnd(collect1.size());
            deviceStructureList.add(collect2.get(0));
        });
        return deviceStructureList;
    }

    /**
     * 生成设备结构
     * @param dataModelList
     * @return
     */
    private List<DeviceStructure> getLinkDeviceStructure(List<LinkDataModel> dataModelList,List<DeviceDto> deviceInfo) {
        List<DeviceStructure> deviceStructureList = new ArrayList<>();
        dataModelList.forEach(linkDataModel -> {
            DeviceStructure deviceStructure = new DeviceStructure();
            deviceStructure.setDeviceId(linkDataModel.getAnedn());
            deviceStructure.setDeviceName(linkDataModel.getAnename());
            List<DeviceStructure> oppositeEnd = getOppositeEnd(dataModelList.stream().filter(
                    linkDataModel1 -> linkDataModel1.getAnedn().equals(linkDataModel.getAnedn())).collect(Collectors.toList()));
            deviceStructure.setOppositeEnd(oppositeEnd.size());// 对端个数
            deviceStructure.setDeviceStructureList(oppositeEnd);
            deviceStructureList.add(deviceStructure);
            DeviceStructure deviceStructure1 = new DeviceStructure();
            deviceStructure1.setDeviceId(linkDataModel.getZnedn());
            deviceStructure1.setDeviceName(linkDataModel.getZnename());
            List<DeviceStructure> oppositeEnd1 = getOppositeEnd1(dataModelList.stream().filter(
                    linkDataModel1 -> linkDataModel1.getZnedn().equals(linkDataModel.getZnedn())).collect(Collectors.toList()));
            deviceStructure1.setOppositeEnd(oppositeEnd1.size());// 对端个数
            deviceStructure1.setDeviceStructureList(oppositeEnd1);
            deviceStructureList.add(deviceStructure1);
        });
        return deviceStructureList;
    }
    /**
     * 获取设备数据
     * @param value
     * @return
     */
    private List<DeviceDto> getDeviceInfo(List<ScreenUser> value) {
        List<DeviceDto> deviceDtoList = new ArrayList<>();
        List<SiteDto> siteData = ModelMapperUtil.strictMapList(redisUtil.getList1(value.get(0).getUserId().concat("_siteData")), SiteDto.class);
        siteData.forEach(siteDto -> {
            List<DeviceDto> device = siteDto.getDevice();
            if (device != null) {
                deviceDtoList.addAll(device);
            }
        });
        return deviceDtoList;
    }

    /**
     * 线程池获取数据
     * @param assemblies
     * @param value
     * @return
     */
    private List<LinkDataModel> threadPool(List<ProgrammeInfoViewDto> assemblies,List<ScreenUser> value) {
        List<LinkDataModel> linkDataModelList = new ArrayList<>();
        assemblies.forEach(programmeInfoViewDto -> {
            if (programmeInfoViewDto.getNumber() == 24) {
                CountDownLatch latch = new CountDownLatch(value.size());
                value.stream().forEach(screenUser -> {
                    // 开启线程池 异步执行任务
                    product.submit(()->{
                        HttpHeaders token = getToken(screenUser);
                        List<LinkDataModel> linkDataModels =  cloudCampusApi.queryLinkInfo(token,screenUser.getDomain());
                        if (linkDataModels != null) {
                            linkDataModelList.addAll(linkDataModels);
                        }
                        latch.countDown();
                    });
                });
                while (true) {
                    // 线程中的任务执行完毕
                    if (latch.getCount() == 0) {
                        log.info("redis 线程执行完毕");
                        break;
                    }
                }
            }
        });
        return linkDataModelList;
    }

    /**
     * 过滤获得设备
     * @param deviceStructure
     * @param deviceInfo
     * @return
     */
    private List<DeviceDto> filterDevice(DeviceStructure deviceStructure,List<DeviceDto> deviceInfo){
        return deviceInfo.stream().filter(deviceDto -> deviceDto.getId().equals(deviceStructure.getDeviceId())).collect(Collectors.toList());
    }
    /**
     * 获取对端设备
     * @param dataModelList
     * @return
     */
    private List<DeviceStructure> getOppositeEnd(List<LinkDataModel> dataModelList){
        List<DeviceStructure> deviceStructureList = new ArrayList<>();
        dataModelList.forEach(linkDataModel -> {
            DeviceStructure deviceStructure = new DeviceStructure();
            deviceStructure.setDeviceId(linkDataModel.getZnedn());
            deviceStructure.setDeviceName(linkDataModel.getZnename());
            deviceStructureList.add(deviceStructure);
        });
        return deviceStructureList;
    }
    /**
     * 获取对端设备
     * @param dataModelList
     * @return
     */
    private List<DeviceStructure> getOppositeEnd1(List<LinkDataModel> dataModelList){
        List<DeviceStructure> deviceStructureList = new ArrayList<>();
        dataModelList.forEach(linkDataModel -> {
            DeviceStructure deviceStructure = new DeviceStructure();
            deviceStructure.setDeviceId(linkDataModel.getAnedn());
            deviceStructure.setDeviceName(linkDataModel.getAnename());
            deviceStructureList.add(deviceStructure);
        });
        return deviceStructureList;
    }

    /**
     * 去重过滤器
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return object -> seen.putIfAbsent(keyExtractor.apply(object), Boolean.TRUE) == null;
    }
    /**
     * 补齐对端的层高
     * @param linkDeviceStructure
     */
    private List<DeviceStructure>  recursive(List<DeviceStructure> linkDeviceStructure) {
        linkDeviceStructure.forEach(deviceStructure -> {
            List<DeviceStructure> collect = deviceStructure.getDeviceStructureList().stream().filter(deviceStructure1 -> deviceStructure1.getLevel() == 1).collect(Collectors.toList());
            if (collect.size() > 0) {
                collect = deviceStructure.getDeviceStructureList().stream().filter(deviceStructure1 -> deviceStructure1.getLevel() != 1).collect(Collectors.toList());
                collect.forEach(deviceStructure1 -> deviceStructure1.setLevel(deviceStructure.getLevel()+1));
            }
        });
        return linkDeviceStructure;
    }

    /**
     * 关联账号成功后就查询一次
     * @param screenUser
     */
    public void getLoginUserDispose(ScreenUser screenUser) {
        List<ScreenUser> screenUsers = new ArrayList<>();
        screenUsers.add(screenUser);
            //筛选出来用户api账号状态正常的获取数据
        if (screenUsers.size() > 0) {
            //根据用户id分组
            Map<String, List<ScreenUser>> map = new HashMap<>();
            screenUsers.stream().collect(Collectors.groupingBy(ScreenUser::getUserId))
                    .forEach(map::put);
            map.entrySet().forEach(userList -> {
                String assemblyInfo = "";
                ProgrammeInfo programmeInfo = new ProgrammeInfo();
                programmeInfo.setUserId(userList.getKey());
                List<ProgrammeInfo> programmeInfos = programmeInfoDao.queryAll(programmeInfo);
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    if (programmeInfo1.getStatus()) {
                        getAssembly(programmeInfo1.getLayoutInfo(),userList.getValue());
                    }
                }
            });

        } else {
            log.info("The Online User list is null!");
        }
    }
    /**
     * 获取组件
     *
     * @param screenUsers
     */
    private void getAssembly(String assemblyInfo ,List<ScreenUser> screenUsers) {
        //根据模板获取组件
        List<ApiAccountDto> apiAccountDtos = new ArrayList<>();
        screenUsers.forEach(screenUser -> {
            ApiAccountDto apiAccountDto = new ApiAccountDto();
            screenUser.setAssemblyInfo(assemblyInfo);
            HttpHeaders requestHeaders = getToken(screenUser);
            //获取站点
            List<SiteDto> sites = cloudCampusApi.getSites(requestHeaders, screenUser.getDomain());
            apiAccountDto.setRequestHeaders(requestHeaders);
            apiAccountDto.setSites(sites);
            apiAccountDto.setScreenUser(screenUser);
            apiAccountDtos.add(apiAccountDto);
        });

        apiAccountDtos.forEach(apiAccountDto -> {
            //获取站点
            List<ProgrammeInfoViewDto> assemblies = JSONArray.parseArray(apiAccountDto.getScreenUser().getAssemblyInfo(), ProgrammeInfoViewDto.class);

            //组件1,3,6,9 组件都是关于站点和设备的，所以走一次方法（1-设备总数柱状图，3-分类型设备数量,6-站点的地图分布,9-设备状态总览）
            //组件4，17，7,8 是关于终端用户的（7-终端用户在线时长，8-有限无线接入人数）

            List<String> list = new ArrayList<>();
            assemblies.forEach(assembly1 -> {
                //站点设备数据
                if (3 == assembly1.getNumber() || 6==assembly1.getNumber() || 9==assembly1.getNumber()) {
                    list.add(String.valueOf(1));
                    //终端接入用户列表（有线无线、在线总人数、 终端流量列表）
                } else if (8 ==assembly1.getNumber() || 4 ==assembly1.getNumber() || 17 ==assembly1.getNumber()) {
                    list.add("7");
                    //流量（日、月、年）
                } else if(15 ==assembly1.getNumber() || 16 ==assembly1.getNumber()){
                    list.add("5");
                    //健康度
                }else if(19 ==assembly1.getNumber() || 20 ==assembly1.getNumber() || 21 ==assembly1.getNumber()){
                    list.add("18");
                }else {
                    list.add(String.valueOf(assembly1.getNumber()));
                }
            });

            //去重
            List<String> list1 = list.stream().distinct().collect(Collectors.toList());
            try {
                if (list1.size() > 0) {
                    list1.forEach(assem -> {
                        AssemblyEnum assemblyEnum = AssemblyEnum.get(assem);
                        switch (assemblyEnum) {
                            //站点的地图分布（默认大屏）
                            case SITE_DEVICE:
                                getSiteDevices(apiAccountDtos);
                                break;
                            //在线人数
                           // case ONLINE:
                               // getRealTimeAccess(apiAccountDtos);
                                //流量
                            case TRAFFIC:
                                getTraffic(apiAccountDtos);
                                break;
                            case APP_TRAFFIC:
                                //查询Top N SSID 流量和最近在线用户数
                                getSsidTraffic(apiAccountDtos);
                                //应用流量
                                //getAppTraffic(apiAccountDtos);
                                break;
                            //终端用户在线时长列表
                            case TERMINAL_USER:
                                getTerminalUserList1(apiAccountDtos);
                                break;
                            case SITE_HEALTH:
                                getSiteHealth(apiAccountDtos);
                                break;
                            default:
                                break;
                        }
                    });
                }
            } catch (Exception e) {
                log.error("the shechedule run error::"+ e.getMessage());

            }

        });

    }



    /**
     * 获取用户token
     *
     * @param screenUser
     */
    public HttpHeaders getToken(ScreenUser screenUser) {

        HttpHeaders requestHeaders = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        requestHeaders.setContentType(type);
        requestHeaders.add("Accept", MediaType.APPLICATION_JSON.toString());

        String userName = screenUser.getTenantName();
        String password = screenUser.getTenantPwd();
        String token = "";

        try {
            if (redisUtil.exist(userName.concat("token"))) {
                token = redisUtil.getValue(userName.concat("token"));
            } else {
                //获取token
                token = cloudCampusApi.getToken(userName, password, requestHeaders, screenUser.getDomain());
                redisUtil.set(userName.concat("token"), 1, token, 10);

            }
            //获取站点
            requestHeaders.add("X-AUTH-TOKEN", token);
            return requestHeaders;
        } catch (Exception e) {
            log.error("token Access failure!");
            return null;
        }

    }


    /**
     * 获取站点设备数据
     *
     * @param
     */
    public void getSiteDevices(List<ApiAccountDto> apiAccountDtos) {
//        System.out.println(apiAccountDtos.get(0).getScreenUser().getUserId()+"我是userId");
        List<DeviceDto> deviceDtos = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<DeviceDto> list = cloudCampusApi.getDevices(sites, requestHeaders, domain);
            if (list != null) {
                deviceDtos.addAll(list);
            }
            allAites.addAll(sites);
        });


        if (deviceDtos != null) {
            //根据站点id 给设备分组
            Map<String, List<DeviceDto>> map = new HashMap<>();
            deviceDtos.stream().collect(Collectors.groupingBy(DeviceDto::getSiteId))
                    .forEach(map::put);

            allAites.forEach(siteDto -> {
                map.entrySet().stream().forEach(siteEntry -> {
                    if (siteDto.getId().equals(siteEntry.getKey())) {
                        siteDto.setDeviceCounts(siteEntry.getValue().size());
                        siteDto.setDevice(siteEntry.getValue());
                    }
                });
            });
        }
        if (allAites != null) {
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_siteData"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_siteData"), allAites);
        }

    }


    /**
     * 获取实时接入用户数
     *
     * @param
     * @param
     */
    private void getRealTimeAccess(List<ApiAccountDto> apiAccountDtos) {
        //获取设备在线人数
//        List<PortalUserDto> portalUserDtos = cloudCampusApi.getProtalUsers(sites, requestHeaders);
        List<RealTimeDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            try {
                List<RealTimeDto> list1 = cloudCampusApi.getDetailMinuDetil(sites, requestHeaders, domain);
                if (list1 != null) {
                    list.addAll(list1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            allAites.addAll(sites);
        });
        if (list != null || list.size() > 0) {
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"), list);
        }

    }


    /**
     * 获取网络流量
     *
     * @param
     * @param
     * @param
     */
    private void getTraffic(List<ApiAccountDto> apiAccountDtos) {
        String requestParmDay = "?timeDimension=day&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByDay()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String requestParmMonth = "?timeDimension=month&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByMonth()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String requestParmYear = "?timeDimension=year&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByYear()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
//        String requestParmHistory = "?timeDimension=year&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByHistory()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String[] requestParms = {requestParmDay, requestParmMonth, requestParmYear};
        String[] keys = {"_traffic", "_trafficMonth", "_trafficYear"};
        for(int i = 0; i < requestParms.length; i++){
            List<RealTimeDto> realTimeDtos = getTrafficByDimension(apiAccountDtos, requestParms[i]);
            if (realTimeDtos.size() > 0) {
                redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat(keys[i]));
                redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat(keys[i]), realTimeDtos);
            }
        }
    }

    /**
     * 获取当日，月，年
     *
     */
    private List<RealTimeDto> getTrafficByDimension(List<ApiAccountDto> apiAccountDtos, String requestParm){
        List<DeviceTrafficDto> deviceTrafficDtos = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<DeviceTrafficDto> list = cloudCampusApi.getDeviceTrafficDetail(sites, requestHeaders, domain, requestParm);
            if (list != null) {
                deviceTrafficDtos.addAll(list);
            }
            allAites.addAll(sites);
        });

        List<RealTimeDto> realTimeDtos = new ArrayList<>();
        allAites.forEach(siteDto -> {
            RealTimeDto realTimeDto = new RealTimeDto();
            realTimeDto.setSiteId(siteDto.getId());
            realTimeDto.setName(siteDto.getName());
            realTimeDto.setValue(0);
            realTimeDtos.add(realTimeDto);
        });

        if (deviceTrafficDtos != null) {
            Map<String, List<DeviceTrafficDto>> map = new HashMap<>();
            deviceTrafficDtos.stream().collect(Collectors.groupingBy(DeviceTrafficDto::getSiteId)).forEach(map::put);
            List<RealTimeDto> list = new ArrayList();
            map.entrySet().forEach(deviceList -> {
                Double siteTraffic = 0d;
                RealTimeDto realTimeDto = new RealTimeDto();
                siteTraffic = deviceList.getValue().stream().collect(Collectors.summingDouble(DeviceTrafficDto::getUpTraffic));
                realTimeDto.setSiteId(deviceList.getKey());
                try {
                    realTimeDto.setValue((int) Math.ceil(siteTraffic));
                }catch (Exception e) {
                    log.error(e.getMessage());
                }
                list.add(realTimeDto);
            });

            if (list.size() > 0) {
                realTimeDtos.forEach(realTimeDto -> {
                    list.forEach(sitesTraffic -> {
                        if ((sitesTraffic.getValue() != null) && realTimeDto.getSiteId().equals(sitesTraffic.getSiteId())) {
                            realTimeDto.setValue(sitesTraffic.getValue());
                        }
                    });
                });
            }
        }
        return realTimeDtos;
    }



    /**
     * 获取TopN应用流量   ----云管理api无数据，暂不使用
     *
     * @param
     * @param
     * @param
     */
    private void getAppTraffic(List<ApiAccountDto> apiAccountDtos) {
        List<AppInfoDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<AppInfoDto> list1 = cloudCampusApi.getAPPTrafficDetail(sites, requestHeaders, domain);
            if (list1 != null) {
                System.out.println("size:"+list1.size());
                list.addAll(list1);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_app_traffic"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_app_traffic"), list);
        }
    }


//    /**
//     * 获取在线时长用户列表
//     *
//     * @param
//     * @param
//     * @param
//     */
//    private void getTerminalUserList(List<ApiAccountDto> apiAccountDtos) {
//
//        List<TerminalUserDto> list = new ArrayList<>();
//        List<SiteDto> allAites = new ArrayList<>();
//        apiAccountDtos.forEach(apiAccountDto -> {
//            List<SiteDto> sites = apiAccountDto.getSites();
//            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
//            String domain = apiAccountDto.getScreenUser().getDomain();
//            List<TerminalUserDto> list1 = cloudCampusApi.getTerminalUserList(sites, requestHeaders, domain);
//            if (list1 != null) {
//                list.addAll(list1);
//            }
//            allAites.addAll(sites);
//        });
//
//        if (list.size() > 0) {
//
//            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_terminal_user"));
//            //存数据
//            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_terminal_user"), list);
//        }
//    }
    private void getTerminalUserList1(List<ApiAccountDto> apiAccountDtos) {
        getTerminalUserList(apiAccountDtos);
        getTerminalUserListOff(apiAccountDtos);
    }

    /**
     * 获取在线时长用户列表
     *
     * @param
     * @param
     * @param
     */
    private void getTerminalUserList(List<ApiAccountDto> apiAccountDtos) {

        List<TerminalUserDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        List<RealTimeDto> realTimeDtoList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            Map online = cloudCampusApi.getTerminalUserList("online", sites, requestHeaders, domain);
            if (online != null) {
                List<RealTimeDto> realTimeDtos = ModelMapperUtil.strictMapList(online.get("realTimeDtos"), RealTimeDto.class);
                List<TerminalUserDto> terminalUserDto = ModelMapperUtil.strictMapList(online.get("TerminalUserDto"), TerminalUserDto.class);
                realTimeDtoList.addAll(realTimeDtos);
                list.addAll(terminalUserDto);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"));
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_online_terminal_user"));
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_online_terminal_user"), list);
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"), realTimeDtoList);
        }
    }
    /**
     * 获取不在线时长用户列表
     *
     * @param
     * @param
     * @param
     */
    private void getTerminalUserListOff(List<ApiAccountDto> apiAccountDtos) {

        List<TerminalUserDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        List<RealTimeDto> realTimeDtoList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            //offline---离线
            Map offline = cloudCampusApi.getTerminalUserList("offline", sites, requestHeaders, domain);
            if (offline != null) {
                List<RealTimeDto> realTimeDtos = ModelMapperUtil.strictMapList(offline.get("realTimeDtos"), RealTimeDto.class);
                List<TerminalUserDto> terminalUserDto = ModelMapperUtil.strictMapList(offline.get("TerminalUserDto"), TerminalUserDto.class);
                realTimeDtoList.addAll(realTimeDtos);
                list.addAll(terminalUserDto);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_realUser"));
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_terminal_user"));
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_terminal_user"), list);
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_realUser"),realTimeDtoList);
        }
    }



    /**
     * 查询TOP N SSID流量和最近在线用户数
     * @param apiAccountDtos
     */
    private void getSsidTraffic(List<ApiAccountDto> apiAccountDtos) {
        List<SiteDto> allAites = new ArrayList<>();
        List<TopNSsidTrafficDto> list = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<TopNSsidTrafficDto> list1= cloudCampusApi.getSsidTrafficDetail(sites, requestHeaders, domain);
            list.addAll(list1);
            allAites.addAll(sites);
        });
        if(list.size()>0){
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_TOPN_SSID_TRAFFIC"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_TOPN_SSID_TRAFFIC"), list);
        }

    }


    /**
     * 站点健康度查询
     * @param apiAccountDtos
     */
    private void  getSiteHealth(List<ApiAccountDto> apiAccountDtos){
        List<SiteHealthDto> siteList = new ArrayList<>();
        List<DeviceHealthDto> deviceList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            siteList.addAll(cloudCampusApi.getSiteHealth(sites, requestHeaders, domain));
            deviceList.addAll(cloudCampusApi.getDeviceHealth(sites, requestHeaders, domain));

        });
        siteList.forEach(siteHealthDto -> {
            deviceList.forEach(deviceHealthDto -> {
                if(siteHealthDto.getSiteId().equals(deviceHealthDto.getSiteId())){
                    siteHealthDto.setDeviceHealthPoint(deviceHealthDto.getDeviceHealthPoint());
                    siteHealthDto.setTimestamp(deviceHealthDto.getTimestamp());
                }
            });
        });
        if(siteList.size()>0){
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_SITE_HEALTH"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_SITE_HEALTH"), siteList);
        }
    }



    private void getLinkAggregation(List<ApiAccountDto> apiAccountDtos){
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            cloudCampusApi.getLinkAggregation(sites, requestHeaders, domain);

        });
    }
}


